15.11 Das Speichern in der Registrierungsdatenbank  
Manchmal möchte man wichtige oder allgemeine Daten einer Form speichern, um das Fenster beim späteren Öffnen wieder in den Zustand zu versetzen, in dem es vor dem Schließen war. Typischerweise gehört dazu die Größe und die Position des Fensters auf dem Bildschirm. Diese Daten sollten spätestens dann gespeichert werden, wenn das Fenster geschlossen wird.
Prinzipiell eignen sich dazu natürlich Dateien, aber das Betriebssystem Windows bietet mit der Registry eine universelle und allgemeine Datenbank an, in die Informationen geschrieben werden können, die nicht verloren gehen dürfen. Wir wollen uns daher jetzt die Klassen ansehen, die es uns ermöglichen, Daten in die Registrierungsdatenbank zu schreiben und sie später bei Bedarf auszuwerten.
15.11.1 Die Klassen »Registry« und »RegistrKey«  
Die Registrierungsdatenbank ist hierarchisch aufgebaut und ähnelt strukturell dem Verzeichnissystem. In der Registry werden die Dateninformationen in Keys (Schlüssel) organisiert, die vergleichbar mit einem Verzeichnis sind. Jeder einzelne Schlüssel kann wieder beliebig viele untergeordnete Unterschlüssel verwalten. In den Unterschlüsseln sind die namentlich gekennzeichneten Dateninformationen enthalten.
Maximal sieben Stammschlüssel sind bei einem Windows-Betriebssystem möglich:
|
HKEY_CLASSES_ROOT |
|
HKEY_CURRENT_USER |
|
HKEY_LOCAL_MACHINE |
|
HKEY_USERS |
|
HKEY_PERFORMANCE_DATA |
|
HKEY_CURRENT_CONFIG |
|
HKEY_DYN_DATA |
Anwendungen beschränken sich meist darauf, Einträge im Unterschlüssel Software des Stammschlüssels HKEY_CURRENT_USER vorzunehmen. Wenn Sie diesen Schlüssel in der Registrierungsdatenbank öffnen (geben Sie dazu unter Start Ausführen... den Dateinamen regedit.exe ein) werden Sie feststellen, dass im Unterschlüssel Software zunächst die Firmennamen eingetragen sind und in den weiteren Unterschlüsseln die Produktnamen.
Die Klasse Registry, die zum Microsoft-spezifischen Namespace Microsoft.Win32 gehört, ermöglicht den Zugriff auf die Stammschlüssel über sieben statische Felder, die schreibgeschützt sind und sich an den Bezeichnern der Stammschlüssel orientieren, beispielsweise:
| Public Shared Readonly ClassesRoot As RegistryKey
|
| Public Shared Readonly LocalMachine As RegistryKey
|
| Public Shared Readonly CurrentUser As RegistryKey
|
Auf die zurückgegebene Referenz vom Typ RegistryKey können Methoden aufgerufen werden, um Unterschlüssel zu erstellen, auf einen Unterschlüssel zuzugreifen oder die in ihm gespeicherten Werte festzulegen oder auszuwerten.
Erstellen eines Unterschlüssels
Zum Erzeugen eines neuen Unterschlüssels dient die Methode CreateSubKey der Klasse RegistryKey, der eine Zeichenfolge übergeben wird, die den Pfad zum Unterschlüssel beschreibt:
| Public Function CreateSubKey(String) As RegistryKey
|
CreateSubKey erzeugt nicht nur einen neuen Unterschlüssel, sondern kann auch einen bereits vorhandenen öffnen. Schlägt die Aktion jedoch fehl, ist der Rückgabewert Nothing.
Wir können beispielsweise mit der folgenden Anweisung im Stammschlüssel HKEY_CURRENT_USER im Unterschlüssel Software gleichzeitig auch zwei hierarchisch angeordnete Unterschlüssel erzeugen:
| Dim regKey As RegistryKey = _
|
| Registry.CurrentUser.CreateSubKey( _
|
| "Software\Tollsoft\MeineAnwendung")
|
regKey verweist danach auf den letzten Unterschlüssel, hier also MeineAnwendung, in dem Sie anschließend die Dateninformationen speichern können.
Öffnen eines untergeordneten Schlüssels
Ein existierender Schlüssel wird mit der Methode OpenSubKey auf eine Referenz vom Typ RegistryKey geöffnet:
| Public Function OpenSubKey(String) As RegistryKey
|
| Public Function OpenSubKey(String, Boolean) As RegistryKey
|
Die erste Variante öffnet einen Schlüssel schreibgeschützt, die zweite erlaubt den schreibenden Zugriff, falls dem booleschem Argument True übergeben wird. Dazu ein Beispiel, um den zuvor erzeugten Unterschlüssel zum Schreiben zu öffnen:
| Dim regKey As RegistryKey = Registry.CurrentUser.OpenSubKey( _
|
| "Software\Tollsoft\MeineAnwendung", True)
|
Die Methode gibt Nothing zurück, wenn der Schlüssel nicht existiert. Sie brauchen daher auch keine Ausnahmebehandlung vorzusehen.
Löschen eines Unterschlüssels
Zum Löschen eines untergeordneten Schlüssels bieten sich zwei Methoden an:
| Public Sub DeleteSubKey(String)
|
| Public Sub DeleteSubKey(String, Boolean)public:
RegistryKey* OpenSubKey(String*, bool);
|
Beiden Methoden wird die Zeichenfolge auf den Unterschlüssel übergeben, den Sie löschen wollen. Es muss sich dabei um einen Unterschlüssel handeln, der selbst keine weiteren Unterschlüssel enthält. Sollte das dennoch der Fall sein, wird eine Ausnahme ausgelöst. Können Sie auf diese Ausnahme public function OpenSubKey(String, Boolean) : RegistryKey; verzichten, bietet sich die Überladung an, die einen booleschen Wert entgegennimmt. Ist dieser True, unterscheidet sich das Verhalten nicht von der einparametrigen Methode, wird False übergeben, wird die Ausnahme nicht ausgelöst.
Würde es nur diese Methode geben, wären mehrere Methodenaufrufe notwendig, um eine weiter verzweigte Unterschlüsselstruktur zu löschen. Deshalb wird von der Klasse RegistryKey auch mit DeleteSubKeyTree eine Methode angeboten, die es erlaubt, einen Schlüssel einschließlich aller Unterschlüssel mit einer einzigen Anweisung zu löschen:
| Public Sub DeleteSubKeyTree(String)
|
Schließen der Registrierung
Mit Close der Klasse RegistryKey wird die Registrierung geschlossen. Alle veränderten Dateninhalte werden dabei zurückgeschrieben:
Werte setzen und lesen
Mit den beiden Methoden SetValue und GetValue können Sie auf die Referenz eines RegistryKey-Objekts im aktuellen Unterschlüssel Werte setzen oder gespeicherte Daten auswerten. Sehen wir uns zuerst die Methode zum Speichern einer Dateninformation an, die allerdings voraussetzt, dass der Schlüssel mit Schreibberechtigung geöffnet worden ist:
| Public Sub SetValue(String, Object)
|
| Public Sub SetValue(String, Object, RegistryKindValue)
|
Der erste Parameter erwartet eine Zeichenfolge. Geben Sie hier den Namen des Werts an, der im zweiten Parameter übergeben wird. Vergleichbar ist der Name eines Werts in der Registrierungsdatenbank mit dem Bezeichner einer Variablen. Im zweiten Parameter wird der Wert übergeben. Da dieser vom Typ Object ist, werden alle Datentypen akzeptiert, z. B.:
| Dim regKey As RegistryKey = Registry.CurrentUser.OpenSubKey( _
|
| "Software\Tollsoft\MeineAnwendung")
|
| regKey.SetValue("x – Position", 0)
|
Neu im .NET Framework 2.0 ist, dass diese Datentypen nun auch unterstützt werden. Grundlage bildet hier die Enumeration RegistryValueKind mit ihren Konstanten.
Tabelle 15.17 Konstanten der Enumeration »RegistryValueKind«
| RegistryValueKind-Member
|
Beschreibung
|
|
Binary
|
Entspricht dem Win32-API-Registrierungsdatentyp REG_BINARY (Binärdaten in beliebiger Form)
|
|
DWord
|
Entspricht dem Win32-API-Registrierungsdatentyp REG_DWORD
(32-Bit-Binärzahl).
|
|
ExpandString
|
Entspricht dem Win32-API-Registrierungsdatentyp REG_EXPAND_SZ (Zeichenfolge, die nicht erweiterte Verweise auf Umgebungsvariablen (z. B. %PATH%) enthält).
|
|
MultiString
|
Entspricht dem Win32-API-Registrierungsdatentyp REG_MULTI_SZ (Array von Zeichenfolgen, das auf zwei Nullzeichen (»00«) endet).
|
|
QWord
|
Entspricht dem Win32-API-Registrierungsdatentyp REG_QWORD (64-Bit-Binärzahl).
|
|
String
|
Entspricht dem Win32-API-Registrierungsdatentyp REG_SZ (eine auf 0 (null) endende Zeichenfolge).
|
|
Unknown
|
Gibt einen nicht unterstützten Registrierungsdatentyp an.
|
Die Methode SetValue unterstützt die Typen durch eine Überladung:
Ausgewertet wird ein bestimmter Wert mit der überladenen Methode GetValue:
| Public Function GetValue(String) As Object
|
| Public Function GetValue(String, Object) As Object
|
| Public Function GetValue(String, Object, RegistryValueKind) As Object
|
Die einparametrige Methode erwartet nur die Namensangabe des gespeicherten Werts. Wird im aktuellen Schlüssel unter diesem Namen kein Eintrag gefunden, ist der Rückgabewert Nothing. Die zweiparametrige Version reagiert anders, wenn der Name nicht gefunden wird. Sie liefert dann den im zweiten Parameter angegebenen Wert, der als Standardwert interpretiert werden kann. Der letzten Überladung teilen Sie im dritten Parameter mit, von welchem Typ der zu lesende Wert ist. Dazu geben Sie eine der Konstanten der Enumeration RegistryValueKind an.
Sie sollten genau beachten, was Sie SetValue übergeben. Eine Objektreferenz anzugeben, wird beim späteren Auswerten scheitern. Denn tatsächlich wird keine Referenz, sondern die Typbeschreibung in die Registrierung geschrieben. Dazu ein Beispiel:
| Dim obj As New ClassA
|
| Dim regKey As RegistryKey = _
|
| Registry.CurrentUser.CreateSubKey("Software\Tollsoft\Test")
|
| regKey.SetValue("Referenz auf ClassA", obj)
|
| ' Registry schließen
|
| regKey.Close()
|
| regKey = _
|
| Registry.CurrentUser.OpenSubKey("Software\Tollsoft\Test")
|
| MessageBox.Show(regKey.GetValue("Referenz auf ClassA"))
|
Die Rückgabe lautet:
Dabei ist MyNamespace der Namespace, in dem ClassA definiert ist. Wir können daraus folgern, dass die von ToString gelieferte Zeichenfolge gespeichert wird.
Weitere Eigenschaften und Methoden von »RegistryKey«
Die wichtigsten Methoden und Eigenschaften der Klasse RegistryKey habe ich Ihnen auf den letzten Seiten vorgestellt. Damit sind die Möglichkeiten aber noch nicht ausgeschöpft. Beispielsweise werden zwei Eigenschaften zur Verfügung gestellt die es ermöglichen, die Anzahl der Unterschlüssel oder die Anzahl der in einem Unterschlüssel eingetragenen Werte abzufragen. Insbesondere wenn sich die Anzahl der Einträge dynamisch ändert, sind diese Eigenschaften von Bedeutung.
In der folgenden Tabelle sind alle typspezifischen Eigenschaften und Methoden der Klasse RegistryKey zusammengefasst, um einen guten Überblick zu vermitteln.
Tabelle 15.18 Eigenschaften und Methoden der Klasse »RegistryKey«
| Eigenschaft/Methode
|
Beschreibung
|
| Close
|
(Methode) Schließt den Schlüssel.
|
| CreateSubKey
|
(Methode) Erstellt einen Unterschlüssel oder öffnet einen vorhandenen.
|
| DeleteSubKey
|
(Methode) Löscht den angegebenen Unterschlüssel.
|
| DeleteSubKeyTree
|
(Methode) Löscht den Unterschlüssel einschließlich aller untergeordneten Unterschlüssel.
|
| DeleteValue
|
(Methode) Löscht den angegebenen Wert aus dem Unterschlüssel.
|
| GetSubKeyNames
|
(Methode) Ruft die Namen aller Unterschlüssel ab.
|
| GetValue
|
(Methode) Ruft den angegebenen Wert ab.
|
| GetValueKind
|
(Methode) Liefert den registrierungsspezifischen Typ eines Wertes.
|
| GetValueNames
|
(Methode) Ruft die Namen aller Werte des angegebenen Unterschlüssels ab.
|
| Name
|
(Eigenschaft) Ruft den Namen des Schlüssels ab.
|
| OpenSubKey
|
(Methode) Ruft einen Unterschlüssel ab.
|
| SetValue
|
(Methode) Legt einen Wert fest.
|
| SubKeyCount
|
(Eigenschaft) Ruft die Anzahl der Unterschlüssel ab.
|
| ValueCount
|
(Eigenschaft) Ruft die Anzahl der Werte im Schlüssel ab.
|
 15.11.2 Programmbeispiel zum Speichern in der Registrierung  
Das Formular des folgenden Beispielprogramms speichert die Positionsdaten Left und Top mit den zuvor beschriebenen Methoden in der Registrierungsdatenbank. Zusätzlich enthält das Formular zwei Eingabetextfelder sowie zwei Kontrollkästchen, deren Inhalt bzw. Einstellungen ebenfalls gespeichert werden. Der im Ereignis FormClosing gespeicherte Zustand wird nach dem erneuten Öffnen des Formulars im Ereignishandler des Load-Ereignisses restauriert.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 15.20 Formular des Beispiels »SaveToRegistry«
| ' ----------------------------------------------------------
|
| ' Beispiel: ...\Kapitel 15\SaveToRegistry
|
| ' ----------------------------------------------------------
|
| Imports Microsoft.Win32
|
| Public Class Form1
|
| Dim key As String = "Software\Tollsoft\MeineAnwendung"
|
| Private Sub Form1_Load(...) Handles MyBase.Load
|
| Dim regKey As RegistryKey = _
|
| Registry.CurrentUser.OpenSubKey(key & "\Position")
|
| ' wenn Subkey nicht existiert, Ereignishandler beenden
|
| If regKey Is Nothing Then
|
| Return
|
| End If
|
| ' Positionsinformationen aus der Registry lesen
|
| Me.Left = regKey.GetValue("x – Position", 0)
|
| Me.Top = regKey.GetValue("y – Position", 0)
|
| ' Inhalt der Steuerelemente restaurieren
|
| regKey = Registry.CurrentUser.OpenSubKey( _
|
| key & "\Position\Controls")
|
| TextBox1.Text = regKey.GetValue("Textbox1", "")
|
| TextBox2.Text = regKey.GetValue("Textbox2", "")
|
| CheckBox1.Checked = _
|
| Convert.ToBoolean(regKey.GetValue("Checkbox1", False))
|
| CheckBox2.Checked = _
|
| Convert.ToBoolean(regKey.GetValue("Checkbox2", False))
|
| End Sub
|
| Private Sub Form1_FormClosing(...) Handles MyBase.FormClosing
|
| ' Positionsinformationen speichern
|
| Dim regKey As RegistryKey = _
|
| Registry.CurrentUser.CreateSubKey(key + "\Position")
|
| regKey.SetValue("x – Position", Me.Left)
|
| regKey.SetValue("y – Position", Me.Top)
|
| ' Steuerelementinhalte speichern
|
| regKey = Registry.CurrentUser.CreateSubKey( _
|
| key + "\Position\Controls")
|
| regKey.SetValue("Textbox1", TextBox1.Text)
|
| regKey.SetValue("Textbox2", TextBox2.Text)
|
| regKey.SetValue("Checkbox1", CheckBox1.Checked)
|
| regKey.SetValue("Checkbox2", CheckBox2.Checked)
|
| regKey.Close()
|
| End Sub
|
| End Class
|
|